package com.xiaomazi.security.config;

import com.xiaomazi.common.utils.R;
import com.xiaomazi.common.utils.ResponseUtil;
import com.xiaomazi.security.entity.SecurityUser;
import com.xiaomazi.security.filter.TokenAuthenticationFilter;
import com.xiaomazi.security.filter.TokenLoginFilter;
import com.xiaomazi.security.handler.MD5PasswordEncoder;
import com.xiaomazi.security.utils.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;


/**
 * @program: llxy-parent
 * @description: 权限配置类
 * @author: 小马子
 * @create: 2023-03-14 12:10
 **/
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    private UserDetailsService userDetailsService;

    private RedisTemplate<String,Object> redisTemplate;

    private MD5PasswordEncoder md5PasswordEncoder;

    @Autowired
    public SecurityConfiguration(UserDetailsService userDetailsService, RedisTemplate<String, Object> redisTemplate, MD5PasswordEncoder md5PasswordEncoder) {
        this.userDetailsService = userDetailsService;
        this.redisTemplate = redisTemplate;
        this.md5PasswordEncoder = md5PasswordEncoder;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(md5PasswordEncoder);
    }

    @Override
    @Bean
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }

    @Bean
    public TokenLoginFilter tokenLoginFilter() throws Exception {
        TokenLoginFilter tokenLoginFilter = new TokenLoginFilter();
        /*登陆路径*/
        tokenLoginFilter.setFilterProcessesUrl("/admin/acl/login");
        /*AuthenticationManager*/
        tokenLoginFilter.setAuthenticationManager(authenticationManager());
        /*成功的回调*/
        tokenLoginFilter.setAuthenticationSuccessHandler((req,resp,authentication)->{
            SecurityUser securityUser = (SecurityUser) authentication.getPrincipal();
            String username = securityUser.getUser().getUsername();
            String token = JwtUtil.createJWT(username);
            redisTemplate.opsForValue().set("login:"+username,securityUser);
            ResponseUtil.out(resp, R.ok().data("token",token));
        });
        /*失败的回调*/
        tokenLoginFilter.setAuthenticationFailureHandler((req,resp,ex)->{
            ResponseUtil.out(resp, R.error().message("用户名或密码错误"));
        });
        return tokenLoginFilter;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .and()
                .logout()
                .logoutUrl("/admin/acl/index/logout")
                .logoutSuccessHandler((req,response,authentication) -> {
                    SecurityUser securityUser = (SecurityUser) authentication.getPrincipal();
                    String username = securityUser.getUser().getUsername();
                    redisTemplate.delete("login:"+username);
                    ResponseUtil.out(response, R.ok().message("登出成功"));
                })
                .and()
                .exceptionHandling().authenticationEntryPoint((req,resp,authEx)->{
                    ResponseUtil.out(resp, R.error().message("认证失败"));
                })
                .and()
                .addFilterAt(tokenLoginFilter(), UsernamePasswordAuthenticationFilter.class)
//                .addFilterBefore(new TokenAuthenticationFilter(redisTemplate),tokenLoginFilter().getClass());
                .addFilterBefore(new TokenAuthenticationFilter(redisTemplate), LogoutFilter.class);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/api/**",
                "/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**"
        );
    }
}
